<?php

namespace App\Kuafu\Order\Service;


use App\Kuafu\Activity\Enum\ActivityEnum;
use App\Kuafu\Base\Model\BaseModel;
use App\Kuafu\Coupon\Enum\CouponEnum;
use App\Kuafu\CouponExt\Enum\CouponExtEnum;
use App\Kuafu\CouponExt\Exceptions\CouponExtException;
use App\Kuafu\CouponExt\Model\OrderCouponExtSplitModel;
use App\Kuafu\CouponPackage\Service\CouponPackageService;
use App\Kuafu\Customer\Enum\PlatformCodeEnum;
use App\Kuafu\Customer\Service\CustomerPlatformService;
use App\Kuafu\CustomerCoupon\Model\CustomerCouponModel;
use App\Kuafu\CustomPayment\Enum\CustomPaymentEnum;
use App\Kuafu\Order\Enum\CodeEnum;
use App\Kuafu\Order\Enum\OrderCodeEnum;
use App\Kuafu\Order\Enum\OrderInfoEnum;
use App\Kuafu\Order\Exceptions\OrderException;
use App\Kuafu\Order\Model\ConsumerOrder;
use App\Kuafu\Order\Model\OrderCouponSplitModel;
use App\Kuafu\Order\Model\OrderDetailSplitModel;
use App\Kuafu\Order\Model\OrderDiscountSplitModel;
use App\Kuafu\Order\Model\OrderExternalSplitModel;
use App\Kuafu\Order\Model\OrderSplitModel;
use App\Kuafu\Order\Model\OrderUserInfoSplitModel;
use App\Kuafu\Pay\Model\PayStreamModel;
use App\Kuafu\Pay\Service\PayService;
use App\Kuafu\User\Exceptions\UserException;
use App\Kuafu\User\Service\AuthService;
use App\Library\SnowFlake\SnowFlake;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

/**
 * 订单操作服务
 * Class OrderOperateService
 * @package App\Kuafu\Order\Service
 */
class OrderHandleService extends OrderBaseSplitService
{
    /**
     * @var int UserId
     */
    private int $userId = 0;

    /**
     * @var OrderCalcService 订单计价
     */
    private OrderCalcService $orderCalc;

    /**
     * @var OrderPay 订单支付
     */
    private OrderPay $orderPay;

    /**
     * @return OrderCalcService
     */
    public function getOrderCalc(): OrderCalcService
    {
        return $this->orderCalc;
    }

    /**
     * @param OrderCalcService $orderCalc
     */
    public function setOrderCalc(OrderCalcService $orderCalc): void
    {
        $this->orderCalc = $orderCalc;
    }

    /**
     * @return OrderPay
     */
    public function getOrderPay(): OrderPay
    {
        return $this->orderPay;
    }

    /**
     * @param OrderPay $orderPay
     */
    public function setOrderPay(OrderPay $orderPay): void
    {
        $this->orderPay = $orderPay;
    }

    /**
     * 微信小程序计价
     * @param $data
     * @throws OrderException
     */
    public function calcPrice($data)
    {
        $this->setOrderCalc(new OrderCalcService($this->brandId, $this->shopId));
        $this->orderCalc = $this->getOrderCalc();

//        dd($data);
        // 订单初始化数据
        $this->orderCalc
            ->initDeliveryType($data) // 配送渠道
            ->initSelfDelivery($data) // 自配送
            ->initUserId($this->userId)
            ->initOrderSourceType($data['sourceType'])
            ->initOrderDetailV3($data)
            ->preCheckGiftProductStock(ActivityEnum::CHANNEL_APPLET) //TODO 预校验赠品库存
            ->initOrderUserCouponV3($data['couponList'])
            ->initCouponPackageId($data['couponPackageId'])
            ->initAnonymousCouponList($data['anonymousCouponList'])
//            ->checkOrderDetailV3()          // 校验订单数据状态
            ->checkOrderCouponStatus()     // 校验优惠券状态
            ->initPostData($data);

        // 自动使用最优优惠券
        $this->autoCoupon($data);

        $this->orderCalc->calcV3();

    }

    /**
     * 抖音小程序计价
     *
     * @param $data
     * @return void
     * @throws OrderException
     */
    public function dyAppletCalcPrice($data)
    {
        $this->setOrderCalc(new OrderCalcService($this->brandId, $this->shopId));
        $this->orderCalc = $this->getOrderCalc();

        // 订单初始化数据
        $this->orderCalc
            ->initUserId($this->userId)
            ->initOrderSourceType($data['sourceType'])
            ->initOrderDetailV3($data)
            ->initAnonymousCouponList($data['anonymousCouponList'])
            ->initOrderCouponExt($data['extCoupon'])
            ->initPostData($data)
            ->calcCustomer([
                'calcOne',
                'calcExtCoupon',
                'calcPayment',
                'calcPackage',
                'calcOrderShouldPrice'
            ]);

    }

    /**
     * @param $data
     * @return void
     * @throws OrderException
     * @throws CouponExtException
     * @throws GuzzleException
     */
    public function checkCouponCalcPrice($data)
    {
        $this->setOrderCalc(new OrderCalcService($this->brandId, $this->shopId));
        $this->orderCalc = $this->getOrderCalc();

        // 订单初始化数据
        $this->orderCalc
            ->initUserId($this->userId)
            ->initOrderSourceType($data['sourceType'])
            ->initOrderDetailV3($data)
            ->initAnonymousCouponList($data['anonymousCouponList'])
            ->initOrderCouponExt($data['extCoupon'])
            ->initPostData($data)
            ->calcCustomer([
                'calcOne',
                'calcExtCoupon',
                'calcPayment',
                'calcPackage',
                'calcOrderShouldPrice'
            ]);
    }


    /**
     * POS 计价
     *
     * @param $data
     * @return array
     * @throws OrderException
     * @throws CouponExtException
     * @throws GuzzleException
     */
    public function calcPosPrice($data): array
    {
        // 获取订单来源
        if (!empty($this->orderInfo)) {
            $data['sourceType'] = $this->orderInfo->sourceType;
        }

        $this->setOrderCalc(new OrderCalcService($this->brandId, $this->shopId, $this->orderId));
        $this->orderCalc = $this->getOrderCalc();

        // 订单初始化数据
        $this->orderCalc
            ->initOrderSourceType($data['sourceType'])
            ->initOrderDetailV3($data)
            ->initOrderDiscount($data['discount'])
            ->initOrderPosTotalPrice($data['totalPrice'])
            ->initOrderCouponExt($data['extCoupon'])
            ->initOrderCouponExtRefund($data['refundCoupon'])
            ->initOrderPosCoupon($data['posCouponList'])
            ->initOrderPosUserCoupon($data)
            ->initOrderPayment($data)
            ->initOrderRefundPayment($data['refundPayMethodList'], $data['orderEvent'] ?? 1)
            ->initOrderRefundPosCouponList($data['refundPosCouponList']);

        // 校验 传入 订单数据
//        $this->orderCalc->checkOrderDetailV3(); // 校验订单数据状态

        //todo 预计算核销用户券使用门槛
        $this->orderCalc->posPreCalculateThreshold();

        $this->orderCalc->checkOrderPosCoupon();// 校验订单使用的优惠券情况
        $this->orderCalc->checkOrderPosUseOneCoupon();// 校验订单使用的优惠券情况


        $this->orderCalc->calcV3(); // 统一计价

        return [
            'price' => $this->orderCalc->getOrderPriceNow(),
        ];
    }

    /**
     * 自动选择优惠券
     *
     * @param $data
     * @throws OrderException
     */
    public function autoCoupon($data)
    {
        $orgCalc               = $this->orderCalc;
        $userCalc              = (clone $orgCalc);
        $bestUserCalcPrice     = 0;
        $bestUserCouponCode    = 0;
        $packageCalc           = (clone $orgCalc);
        $bestPackageCalcPrice  = 0;
        $bestPackageCouponCode = 0;
        $bestUseCoupon         = [];//用户券使用组合
        $bestUsePackageCoupon  = [];//券包券使用组合

        $bestType = 0;

        // empty(自动选择券) √
        // empty(用户选择券) √
        // empty(券包选择券) √

        // todo  获取当前订单可用优惠券列表
        $couponList = $this->orderCalc->getUserOrderAllCoupon();
        // todo 获取客户端预选择商品券
        $preSelectedExchangeCouponCode = attributeGet($data, "couponList.0.couponCode", "");
        // todo 判断客户端预选 且有且只选了一张商品券
        $selectedExchangeCoupon = count($data["couponList"]) <= 1 && collect($couponList['enableCouponList'])
                ->where("couponType", CouponEnum::COUPON_TYPE_EXCHANGE)
                ->where("couponCode", attributeGet($data, "couponList.0.couponCode", ""))
                ->first();

        if ($data['isAutoCoupon'] && (empty($data['couponList']) || $selectedExchangeCoupon) && empty($data['anonymousCouponList'])) {
            // 自动选择券
            if (!empty($couponList['enableCouponList'])) {
                list(
                    $preUseExchangeCouponCode,
                    $remainingOrderTotalPrice,
                    $canUseNonExchangeCoupon
                    ) = $this->preUseUserExchangeCoupon($couponList['enableCouponList'],
                    $preSelectedExchangeCouponCode);

                if ($preUseExchangeCouponCode) {
                    $baseUseCoupon = [["couponCode" => $preUseExchangeCouponCode]];
                } else {
                    $baseUseCoupon = [];
                }

                if ($canUseNonExchangeCoupon) {
                    // todo  循环能与商品券组合使用的其他类型优惠券统计计价 & 判断最优价格
                    foreach ($canUseNonExchangeCoupon as $key => $coupon) {
                        $cloneOrderCalc = (clone $userCalc);

                        $autoCoupon = collect($baseUseCoupon)
                            ->merge([['couponCode' => $coupon['couponCode']]])
                            ->values()
                            ->toArray();

                        $cloneOrderCalc->initOrderUserCouponV3($autoCoupon);
                        $cloneOrderCalc->calcV3(); // 统一计价
                        $thisShouldPrice = $cloneOrderCalc->getOrderPriceNow()['orderShouldPrice'];

                        // 第一次请求
                        if ($key == 0) {
                            $bestUserCalcPrice = $thisShouldPrice;
                            $bestUseCoupon     = $autoCoupon;
                            continue;
                        }
                        // 取 最优方案
                        if ($bestUserCalcPrice > $thisShouldPrice) {
                            $bestUseCoupon     = $autoCoupon;
                            $bestUserCalcPrice = $thisShouldPrice;
                        }
                    }
                } else {
                    $bestUseCoupon = $baseUseCoupon;
                }


//                // 循环计价 判断最优价格
//                foreach ($couponList['enableCouponList'] as $key => $coupon) {
//                    $cloneOrderCalc = (clone $userCalc);
//
//                    $autoCoupon = [['couponCode' => $coupon['couponCode']]];
//                    $cloneOrderCalc->initOrderUserCouponV3($autoCoupon);
//                    $cloneOrderCalc->calcV3(); // 统一计价
//                    $thisShouldPrice = $cloneOrderCalc->getOrderPriceNow()['orderShouldPrice'];
//
//                    // 第一次请求
//                    if ($key == 0) {
//                        $bestUserCalcPrice  = $thisShouldPrice;
//                        $bestUserCouponCode = $coupon['couponCode'];
//                        continue;
//                    }
//                    // 取 最优方案
//                    if ($bestUserCalcPrice > $thisShouldPrice) {
//                        $bestUserCouponCode = $coupon['couponCode'];
//                    }
//
//                }
                unset($key);

                // 重置选择最优计价
                $userCalc->initOrderUserCouponV3($bestUseCoupon);
                $bestType = 1;
            }
        }

        // 是否有券包信息 如果有 计算券包最优价格
        if ($data['isAutoCoupon']
            && !empty($data['couponPackageId'])
            && empty($data['anonymousCouponList'])
            && empty($data['couponList'])
        ) {
            $couponList = $this->orderCalc->getCouponPackageCouponList();
            $couponList = array_values($couponList);

            // todo 预选择最大面值商品券
            list(
                $preUseExchangeCouponId,
                $remainingOrderTotalPrice,
                $canUseNonExchangeCoupon
                ) = $this->preUseCouponPackageExchangeCoupon($couponList);

            // todo 存在预选择的商品券  则作为基础用券
            if ($preUseExchangeCouponId) {
                $baseUseCoupon = [['couponId' => $preUseExchangeCouponId, 'num' => 1]];
            } else {
                $baseUseCoupon = [];
            }

            if (!empty($canUseNonExchangeCoupon)) {
                // ToDo (预选择商品券 + 可用非商品券) 组合循环计价
                foreach ($canUseNonExchangeCoupon as $key => $list) {
                    $autoCoupon     = collect($baseUseCoupon)->merge([['couponId' => $list['id'], 'num' => 1]])
                                                             ->toArray();
                    $cloneOrderCalc = (clone $packageCalc);

                    $cloneOrderCalc->initOrderPosCoupon(
                        $autoCoupon,
                        OrderCouponSplitModel::COUPON_SOURCE_COUPON_PACKAGE
                    );
                    $cloneOrderCalc->calcV3(); // 统一计价
                    $thisShouldPrice = $cloneOrderCalc->getOrderPriceNow()['orderShouldPrice'];

                    // 第一次请求
                    if ($key == 0) {
                        $bestPackageCalcPrice = $thisShouldPrice;
                        $bestUsePackageCoupon = $autoCoupon;
                        continue;
                    }

                    // 取 最优方案
                    if ($bestPackageCalcPrice > $thisShouldPrice) {
                        $bestUsePackageCoupon = $autoCoupon;
                        $bestPackageCalcPrice = $thisShouldPrice;
                    }
                }

                // 重置选择最优计价
                $packageCalc->initOrderPosCoupon(
                    $bestUsePackageCoupon,
                    OrderCouponSplitModel::COUPON_SOURCE_COUPON_PACKAGE
                );

                if ($bestType == 0) {
                    // 覆盖用户的选择的券
                    $packageCalc->setOrderUserCoupon([], true);
                    $bestType = 2;
                } else {
                    if ($bestPackageCalcPrice > $bestUserCalcPrice) {
                        $bestType = 1;
                    } else {
                        $bestType = 2;
                    }
                }
            }
        }

        switch ($bestType) {
            case 0:
                break;
            case 1:
                $this->orderCalc = $userCalc;
                break;
            case 2:
                $this->orderCalc = $packageCalc;
                break;
        }
    }

    /**
     * 用户已有优惠券 -》 预使用商品券 & 剔除商品券剩余金额
     *
     * @param array $couponLists
     * @param string $selectedExchangeCode
     * @return array
     * @throws OrderException
     */
    public function preUseUserExchangeCoupon(array $couponLists, string $selectedExchangeCode = ""): array
    {
        //todo 获取最大面值商品券 || 客户端已选择商品券
        if ($selectedExchangeCode) {
            $selectedExchangeCoupon = collect($couponLists)
                ->where("couponType", CouponEnum::COUPON_TYPE_EXCHANGE)
                ->where("couponCode", $selectedExchangeCode)
                ->first();
        } else {
            $selectedExchangeCoupon = collect($couponLists)
                ->where("couponType", CouponEnum::COUPON_TYPE_EXCHANGE)
                ->sortByDesc("discount")
                ->sortBy("endAt")
                ->first();
        }

        // todo 计算订单使用最大面值商品券后剩余总价 & 剩余商品信息
        list($remainingOrderTotalPrice, $remainingOrderProducts) = $this->calculateUsedMaxExchangeCouponPrice($selectedExchangeCoupon ?? []);

        // todo 获取剩余可使用的非商品券
        $canUseNonExchangeCoupon = collect($couponLists)->whereIn("couponType",
            [CouponEnum::COUPON_TYPE_VOUCHERS, CouponEnum::COUPON_TYPE_DISCOUNT]
        )->filter(function ($coupon) use ($remainingOrderProducts) {
            // 券可使用商品
            $couponUseProducts = array_filter(explode(",", $coupon["canUseProduct"]));
            // 券可使用商品总价
            $couponUseProductsPrice = $this->calculateSelectedProductsPrice(
                $remainingOrderProducts,
                $couponUseProducts
            );
            // 券可使用商品总价大于0 && （无门槛 or  券可使用商品总价大于门槛）
            if ($couponUseProductsPrice > 0 && ($coupon["useCondition"] == 0 || $couponUseProductsPrice >= $coupon["useCondition"])) {
                return true;
            } else {
                return false;
            }
        })->values()->sortBy("endAt")->values()->toArray();

        return [
            attributeGet($selectedExchangeCoupon, "couponCode", ""), //预使用商品券券码
            $remainingOrderTotalPrice,//剔除使用商品券剩余金额
            $canUseNonExchangeCoupon//返回 可使用折扣券&代金券信息
        ];
    }

    /**
     * 券包券 -》 预选中最大面值商品券 && 留下使用最大面值商品券后剩余可用的其他类型券
     *
     * @param array $couponLists
     * @param int $selectedExchangeCouponId
     * @return array
     * @throws OrderException
     */
    public function preUseCouponPackageExchangeCoupon(array $couponLists, int $selectedExchangeCouponId = 0): array
    {
        //todo 获取最大面值商品券 || 客户端已选择商品券
        if ($selectedExchangeCouponId) {
            $selectedExchangeCoupon = collect($couponLists)
                ->where("type", CouponEnum::COUPON_TYPE_EXCHANGE)
                ->first();
        } else {
            $selectedExchangeCoupon = collect($couponLists)
                ->where("type", CouponEnum::COUPON_TYPE_EXCHANGE)
                ->sortByDesc("discount")
                ->first();
        }

        // todo 计算订单使用最大面值商品券后剩余总价 & 剔除使用商品券商品后剩余商品信息
        list($remainingOrderTotalPrice, $remainingOrderProducts) = $this->calculateUsedMaxExchangeCouponPrice($selectedExchangeCoupon ?? []);

        // todo 获取剩余可使用的非商品券
        $canUseNonExchangeCoupon = collect($couponLists)->whereIn("type",
            [CouponEnum::COUPON_TYPE_VOUCHERS, CouponEnum::COUPON_TYPE_DISCOUNT]
        )->filter(function ($coupon) use ($remainingOrderProducts) {
            // 券可使用商品
            $couponUseProducts = array_filter(explode(",", $coupon["canUseProduct"]));
            // 券可使用商品总价
            $couponUseProductsPrice = $this->calculateSelectedProductsPrice($remainingOrderProducts,
                $couponUseProducts);
            // 券可使用商品总价大于0 && （无门槛 or  券可使用商品总价大于门槛）
            if ($couponUseProductsPrice > 0 && ($coupon["useCondition"] == 0 || $couponUseProductsPrice >= $coupon["useCondition"])) {
                return true;
            } else {
                return false;
            }
        })->values()->toArray();

        return [
            attributeGet($selectedExchangeCoupon, "id", ""), //预使用优惠券id
            $remainingOrderTotalPrice,//剔除使用商品券剩余金额
            $canUseNonExchangeCoupon//返回 可使用折扣券&代金券信息
        ];
    }

    /**
     * 获取使用最大面值商品兑换券后剩余商品总价
     *
     * @param array $selectedExchangeCoupon
     * @return array
     * @throws OrderException
     */
    public function calculateUsedMaxExchangeCouponPrice(array $selectedExchangeCoupon): array
    {
        $remainingOrderTotalPrice = 0;
        $productLists             = $this->orderCalc->getProductLists();
        $decrease                 = false;
        $remainingOrderProducts   = collect($productLists)->map(function ($product) use (
            $selectedExchangeCoupon,
            &$decrease,
            &$remainingOrderTotalPrice
        ) {
            // todo 剔除使用券产品
            if (
                $selectedExchangeCoupon
                &&
                $selectedExchangeCoupon["canUseProduct"] == $product["productId"]
                &&
                $decrease == false
            ) {
                $product["number"] = $product["number"] - 1;
                $decrease          = true;
            }
            $remainingOrderTotalPrice += ($product["number"] * $product["price"]);
            return $product;
        })->values()->toArray();

        return [$remainingOrderTotalPrice, $remainingOrderProducts];
    }

    /**
     * 计算传入商品中选中商品的总价 不传选中商品则返回总价
     *
     * @param array $products 所有商品
     * @param array $selectedProductIds 选中商品
     * @return float|int
     */
    public function calculateSelectedProductsPrice(array $products, array $selectedProductIds = [])
    {
        $totalPrice = 0;
        collect($products)->when($selectedProductIds, function ($query) use ($selectedProductIds) {
            return $query->whereIn("productId", $selectedProductIds);
        })->each(function ($product) use (&$totalPrice) {
            $totalPrice += (bcsub($product["number"], $product["freeNum"]) * $product["price"]);
        });
        return $totalPrice;
    }

    public function handleOrder($data)
    {
        // 判断是否再下单
        if (empty($data['orderId'])) {
            // 生成订单
            $this->createOrder($data);
        } else {
            // 更新订单
            $this->updateOrder($data);
        }
    }

    /**
     * pos 支付
     *
     * @param $postData
     * @return array|string[]
     * @throws OrderException
     */
    public function posPay($postData): array
    {
        // 支付订单
        $orderPay = new OrderPay($this->brandId, $this->shopId, $this->getOrderId());
        $this->setOrderPay($orderPay);

        // 判断支付方式
        if (empty($postData['payMethod'])) {
            return [];
        }

        // 支付上锁
        $orderPay->lockPay($postData['payMethod']);

        switch ($postData['payMethod']) {
            case CodeEnum::ORDER_PAY_CHANNEL_ALIPAY:            // 支付宝
            case CodeEnum::ORDER_PAY_CHANNEL_WECHAT:            // 微信
            case CodeEnum::ORDER_PAY_CHANNEL_UNION_PAY:            // 云闪付
                $payAuthCode = $postData['payAuthCode'] ?? '';
                $orderPay->setPayData([
                    'payMethod'   => CodeEnum::ORDER_PAY_CHANNEL_WECHAT,
                    'payEvent'    => CodeEnum::ORDER_PAY_EVENT_ORDER,
                    'payAuthCode' => $payAuthCode
                ]);
                $result = $orderPay->barPay();
                break;
            case CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK:          // 试吃
            case CodeEnum::ORDER_PAY_CHANNEL_MONEY:             // 现金支付
                $orderPay->setPayData([
                    'payMethod' => CodeEnum::ORDER_PAY_CHANNEL_MONEY,
                    'payEvent'  => CodeEnum::ORDER_PAY_EVENT_ORDER
                ]);
                $result = $orderPay->cashPay();
                $orderPay->successV2();
                $orderPay->finish();

                break;
            case CodeEnum::ORDER_PAY_CHANNEL_WECHAT_MINI:       // 生成小程序二维码
                $result = $orderPay->genAppletQrCode();
                break;
            default:
                $result = [];
        }
        return $result;
    }

    /**
     * 创建订单 入库
     *
     * @param $data
     * @return array[]
     * @throws UserException
     */
    public function createOrder($data): array
    {
        $this->orderId = SnowFlake::nextIdCache();
        DB::connection(OrderDb::orderDbConnection($this->shopId))->beginTransaction();
        try {
            // 订单表
            $orderData = $this->getInsertOrderData($data);
            OrderSplitModel::suffix($this->shopId)->insertOrder($orderData);

            // 订单详情
            $orderDetailData = $this->getInsertOrderDetailData($data);
            OrderDetailSplitModel::suffix($this->shopId)->insertOrderDetail($orderDetailData);

            // 整单优惠
            $orderDiscountData = $this->getInsertOrderDiscount($data);
            OrderDiscountSplitModel::suffix($this->shopId)->insertOrderDiscount($orderDiscountData);

            // 内部优惠券
            $orderCouponData = $this->getInsertOrderCouponData($data);
            OrderCouponSplitModel::suffix($this->shopId)->insertOrderCoupon($orderCouponData);

            // 生成 券包关联订单
            $orderCouponPackageOrder = $this->InsertOrderCouponPackage($data);

            // 生成 关联 订单
            $orderCouponPackage = $this->getInsertOrderExternal($data, $orderCouponPackageOrder);
            OrderExternalSplitModel::suffix($this->shopId)->insertOrderExternal($orderCouponPackage);

            // 自定义支付流水表写入/更新
            $orderCustomPayment = $this->getInsertCustomPaymentList($data);
            $this->payCustomPayment($orderCustomPayment);

            // 锁定 用户优惠券
            CustomerCouponModel::lockCustomerCoupon($this->orderCalc->getOrderUserCoupon('id'));

            DB::connection(OrderDb::orderDbConnection($this->shopId))->commit();

            // 小程序用户订单单独添加
            $consumerOrderData = $this->getCustomerOrderData($orderData, $orderDetailData);
            ConsumerOrder::insertOrder($consumerOrderData);

            // 自配送等相关信息
            $selfDeliveryData = $this->getInsertSelfDelivery($data);
            OrderUserInfoSplitModel::suffix($this->shopId)->insertOrderUserInfo($selfDeliveryData);

            Log::channel('order')->debug('orderHandleService-createOrder', [
                '$orderData'         => $orderData,
                '$orderDetailData'   => $orderDetailData,
                '$orderDiscountData' => $orderDiscountData,
                '$orderCouponData'   => $orderCouponData,
                '$consumerOrderData' => $consumerOrderData,
                '$selfDeliveryData'  => $selfDeliveryData
            ]);

        } catch (\Exception $exception) {
            DB::connection(OrderDb::orderDbConnection($this->shopId))->rollback();
            Log::channel('order')->error('订单入库失败', [
                $exception->getMessage()
            ]);
            throw new OrderException(OrderCodeEnum::ERR_ORDER_ADD_ERROR, '下单失败', $exception);
        }

        return [
            'orderId' => $this->orderId
        ];
    }

    /**
     * 更新订单 入库
     *
     * @param $data
     * @return array[]
     * @throws UserException
     */
    public function updateOrder($data): array
    {
        DB::connection(OrderDb::orderDbConnection($this->shopId))->beginTransaction();
        try {
            // 订单表
            $orderData = $this->getInsertOrderData($data, true);
            OrderSplitModel::suffix($this->shopId)
                           ->updateOrder($orderData);

            // 订单详情
            $orderDetailData = $this->getInsertOrderDetailData($data, true);
            OrderDetailSplitModel::suffix($this->shopId)
                                 ->updateOrderDetail($this->getOrderId(true), $orderDetailData);

            // 整单优惠
            $orderDiscountData = $this->getInsertOrderDiscount($data, true);
            OrderDiscountSplitModel::suffix($this->shopId)
                                   ->updateOrderDiscount($this->getOrderId(true), $orderDiscountData);

            // 内部优惠券信息
            $orderCouponData = $this->getInsertOrderCouponData($data, true);
            OrderCouponSplitModel::suffix($this->shopId)
                                 ->updateOrderCoupon($this->getOrderId(true), $orderCouponData);

            // [三方优惠券] 获取更新数据信息
            $orderExtCouponData = $this->getInsertOrderExtCouponData($data, true);
            OrderCouponExtSplitModel::suffix($this->shopId)
                                    ->updateOrderExtCoupon($this->getOrderId(true), $orderExtCouponData);

            // 自定义支付流水表写入/更新
            $orderCustomPayment = $this->getInsertCustomPaymentList($data, true);
            $this->payCustomPayment($orderCustomPayment);

            // 退款自定义支付流水
            $orderRefundCustomPayment = $this->getInsertRefundCustomPaymentList($data, true);
            $this->refundCustomPayment($orderRefundCustomPayment);

            DB::connection(OrderDb::orderDbConnection($this->shopId))->commit();
            // 退券
            $orderCouponDataCustomerCouponIdIds = $this->getOrderRefundCouponField('customerCouponId');
            OrderCouponSplitModel::suffix($this->shopId)
                                 ->cancelOrderCouponById($orderCouponDataCustomerCouponIdIds);
            // 锁定 用户优惠券
            CustomerCouponModel::lockCustomerCoupon($this->orderCalc->getOrderUserCoupon('id'));

            // 退款支付宝微信流水
            $orderUserSideRefundPayment = $this->getInsertRefundUserSidePaymentList();
            $this->refundUserSideOrderPayment($orderUserSideRefundPayment);

//            // 判断是否存在 userId
            if ($this->orderInfo->userId) {
                ConsumerOrder::query()->updateOrCreate(
                    [
                        'orderId' => (int)$this->orderInfo->orderId
                    ],
                    [
                        'originalPrice'    => $orderData['originalPrice'],
                        'discountPrice'    => $orderData['discountPrice'],
                        'shouldPrice'      => $orderData['shouldPrice'],
                        'orderShouldPrice' => $orderData['orderShouldPrice'],
                    ]
                );
            }

            Log::channel('order')->debug('OrderHandleService-updateOrder', [
                '$orderData'                          => $orderData,
                '$orderDetailData'                    => $orderDetailData,
                '$orderDiscountData'                  => $orderDiscountData,
                '$orderCouponData'                    => $orderCouponData,
                '$orderExtCouponData'                 => $orderExtCouponData,
                '$orderCustomPayment'                 => $orderCustomPayment,
                '$orderRefundCustomPayment'           => $orderRefundCustomPayment,
                '$orderCouponDataCustomerCouponIdIds' => $orderCouponDataCustomerCouponIdIds,
                '$orderUserSideRefundPayment'         => $orderUserSideRefundPayment
            ]);

        } catch (\Exception $exception) {
            DB::connection(OrderDb::orderDbConnection($this->shopId))->rollback();
            Log::channel('order')->error('updateOrder_error', [
                'postData' => $data,
                'errMsg'   => $exception
            ]);
            throw new OrderException(OrderCodeEnum::ERR_ORDER_ADD_ERROR, '更新订单失败');
        }

        return [
            'orderId' => $this->orderId
        ];
    }


    /**
     * 根据三方订单获取信息
     *
     * @param string $thirdOrderId
     * @param int $thirdOrderSource
     * @return mixed
     */
    public function getOrderInfoByThirdOrderId(
        string $thirdOrderId,
        int $thirdOrderSource = CodeEnum::THIRD_ORDER_SOURCE_DY
    ) {
        return OrderSplitModel::suffix($this->shopId)
                              ->where('thirdOrderId', $thirdOrderId)
                              ->where('thirdOrderSource', $thirdOrderSource)
                              ->first();
    }

    /**
     * 更新三方订单信息
     *
     * @param $data
     * @return array
     * @throws OrderException
     */
    public function updateThirdOrderInfo($data): array
    {
        DB::connection(OrderDb::orderDbConnection($this->shopId))->beginTransaction();
        try {
            // 订单表
            $orderData = [
                'orderId'          => $this->getOrderId(true),
                'thirdOrderId'     => $data['order']['thirdOrderId'],
                'thirdOrderSource' => $data['order']['thirdOrderSource'],
            ];

            OrderSplitModel::suffix($this->shopId)
                           ->updateOrder($orderData);

            DB::connection(OrderDb::orderDbConnection($this->shopId))->commit();

            Log::channel('order')->debug('OrderHandleService-updateThirdOrderInfo', [
                '$orderData' => $orderData,
            ]);

        } catch (\Exception $exception) {
            DB::connection(OrderDb::orderDbConnection($this->shopId))->rollback();
            Log::channel('order')->error('updateOrder_error', [
                'postData' => $data,
                'errMsg'   => $exception
            ]);
            throw new OrderException(OrderCodeEnum::ERR_ORDER_ADD_ERROR, '更新三方订单订单失败');
        }

        return [
            'orderId' => $this->orderId
        ];
    }

    /**
     * 创建订单-离线订单 入库
     *
     * @param $data
     * @return array[]
     * @throws UserException
     */
    public function createOrderOffline($data): array
    {
        try {
            // 格式化 订单表
            $orderData       = OrderOfflineService::formatOfflineOrderInputData($data);
            $data['orderId'] = $orderData['orderId'];

            // 获取菜品所有分类
            OrderOfflineService::setAllCategoryWithDel($data['menuId']);
            // 格式化 菜品详情
            $orderDetailData = OrderOfflineService::formatOfflineOrderDetailInputData($data);

            // 格式化 整单优惠, 自定义支付优惠
            // 重新计算整单打折优惠金额
            if (!empty($data['discount'] && $data['discount']['discountType'] == CodeEnum::ORDER_DISCOUNT_TYPE_COUNT)) {
                $calcOriginPrice = 0;
                foreach ($orderDetailData as $detail) {
                    if ($detail['freeNum'] == 0 && $detail['packageDetailId'] == 0) {
                        $calcOriginPrice += $detail['originalPrice'];
                    }
                }

                $discountCalcPrice = bcmul($calcOriginPrice, (1 - $data['discount']['discountNum'] / 100), 2);

                $data['discount']['discountPrice'] = OrderService::calcInter($data['shopId'], $discountCalcPrice);
            }

            // 倒退自定义试吃金额
            if ($data['payMethod'] == CodeEnum::ORDER_PAY_CHANNEL_TRY_TACK) {
                $tryPayPrice = $data['totalPrice']['originalPrice'];
                foreach ($orderDetailData as $detail) {
                    if ($detail['freeNum'] > 0 && $detail['packageDetailId'] == 0) {
                        $tryPayPrice -= $detail['originalPrice'];
                    }
                }

                $data['totalPrice']['payPrice'] = $tryPayPrice;
            }

            $orderDiscountData = OrderOfflineService::formatOfflineOrderDiscountInputData($data);

            // 格式化 自定义 支付方式 然后入流水
            $orderCustomPayment = OrderOfflineService::formatOfflineOrderCustomPaymentInputData($data);

            DB::connection(OrderDb::orderDbConnection($this->shopId))->beginTransaction();
            // 订单入库
            OrderSplitModel::suffix($this->shopId)->insertOrderAfterFormat($orderData);
            // 菜品入库
            OrderDetailSplitModel::suffix($this->shopId)->insertOrderDetailAfterFormat($orderDetailData);
            // 整单优惠入库
            OrderDiscountSplitModel::suffix($this->shopId)->insertOrderDiscountAfterFormat($orderDiscountData);
            // 离线支付入库
            OrderOfflineService::handleOfflineOrderCustomPayment($orderCustomPayment);

            DB::connection(OrderDb::orderDbConnection($this->shopId))->commit();

            Log::channel('order')->debug('orderHandleService-createOrderOffline', [
                '$orderData'          => $orderData,
                '$orderDetailData'    => $orderDetailData,
                '$orderDiscountData'  => $orderDiscountData,
                '$orderCustomPayment' => $orderCustomPayment
            ]);

        } catch (\Exception $exception) {

            DB::connection(OrderDb::orderDbConnection($this->shopId))->rollback();
            Log::channel('order')->error('离线-订单入库失败~', [
                'offOrderId' => $data['orderId'],
                'file'       => $exception->getFile(),
                'line'       => $exception->getLine(),
                'msg'        => $exception->getMessage(),
            ]);
            throw new OrderException(OrderCodeEnum::ERR_ORDER_ADD_ERROR, '离线订单失败', $exception);
        }

        return [
            'orderId' => $this->orderId
        ];
    }

    /**
     * 针对预计价用的 用户有的券信息
     *
     * @return array
     * @throws OrderException
     */
    public function getUserCoupon(): array
    {
        $userCouponList = $this->orderCalc->getUserOrderAllCoupon();
        $userCouponList = OrderService::addCouponSourceType($userCouponList,
            OrderCouponSplitModel::COUPON_SOURCE_APPLET);

        $couponPackageCouponList = [
            'enableCouponList'  => $this->orderCalc->getCouponPackageCouponList(),
            'disableCouponList' => $this->orderCalc->getCouponUnablePackageCouponList()
        ];

        // 如果用户选择了自己的券, 券包都置为不可用, 用户自己的不管
        if (!empty($this->orderCalc->getOrderUserCoupon())) {
            $couponPackageCouponList['disableCouponList'] += $couponPackageCouponList['enableCouponList'];
            $couponPackageCouponList['enableCouponList']  = [];
        }
        // 如果用户选择了券包的券,则自己的券不能用
        if (!empty($this->orderCalc->getOrderPosCoupon())) {
            $userCouponList['disableCouponList'] += $userCouponList['enableCouponList'];
            $userCouponList['enableCouponList']  = [];

            // 过滤已使用的券信息
            $hasUsed   = $this->orderCalc->getOrderPosCoupon();
            $hasUsedId = array_column($hasUsed, 'id');

            foreach ($couponPackageCouponList['enableCouponList'] as $key => $coupon) {
                if (!in_array($coupon['id'], $hasUsedId)) {
                    $couponPackageCouponList['disableCouponList'][] = $coupon;
                    unset($couponPackageCouponList['enableCouponList'][$key]);
                }
            }
        }

        $userCouponList          = $this->formatOutCouponList($userCouponList);
        $couponPackageCouponList = $this->formatOutCouponList($couponPackageCouponList);

        $result = [
            'user'          => $userCouponList,
            'couponPackage' => $couponPackageCouponList
        ];

        return $result;
    }

    public function getUserUsedCoupon()
    {
        return $this->orderCalc->getOrderUserCoupon();
    }

    public function getPosUsedCoupon()
    {
        return $this->orderCalc->getOrderPosCoupon();
    }

    public function getOrderPrice(): array
    {
        return $this->orderCalc->getOrderPriceNow();
    }

    public static function getPosOrderPaymentList($orderInfo): array
    {
        $paymentList = [];

//        dd($orderInfo->orderCouponExtRel);

        foreach ($orderInfo->orderCouponExtRel as $coupon) {
            $paymentList[] = self::formatOrderPosCouponExt($coupon);
        }

        foreach ($orderInfo->orderCouponRel as $coupon) {
            $paymentList[] = self::formatOrderPosCoupon($coupon);
        }

        foreach ($orderInfo->orderPayStreamRel as $coupon) {
            $paymentList[] = self::formatOrderPosPayStream($coupon);
        }

        foreach ($orderInfo->orderRefundStreamRel as $coupon) {
            $paymentList[] = self::formatOrderPosRefundStream($coupon);
        }

        $paymentList = array_filter($paymentList);

        $paymentList = OrderService::arraySort($paymentList, 'createdAt', SORT_ASC);

        return $paymentList;
    }

    public static function getPosOrder($data): array
    {
        if (empty($data['orderId'])) {
            return [];
        }

        $result = [
            'orderId'       => (string)$data['orderId'],
            'serialNum'     => $data['serialNum'],
            'originalPrice' => $data['originalPrice'],
            'shouldPrice'   => $data['shouldPrice'],
            'discountPrice' => $data['discountPrice'],
            'payPrice'      => $data['payPrice'],
            'orderStatus'   => $data['orderStatus'],
            'refundStatus'  => $data['refundStatus'],
            'payStatus'     => $data['payStatus']
        ];
        return $result;
    }

    public static function baseFormatOrderPosData(array $data): array
    {
        return [
            'id'            => (string)$data['id'] ?? '',
            'name'          => $data['name'] ?? '',
            'status'        => (int)($data['status'] ?? 0),
            'paymentType'   => $data['paymentType'], // 支付类型
            'paymentId'     => $data['paymentId'] ?? 0, // 支付 ID
            'payPrice'      => $data['payPrice'] ?? 0, // 折扣金额
            'costPrice'     => $data['costPrice'] ?? 0, // 成本金额
            'createdAt'     => $data['createdAt'] ?? 0, // 时间,用于排序,
            'couponType'    => $data['couponType'] ?? 0, // 默认为 0 券类型 1代金券 2 商品兑换券 3 折扣券
            'couponNum'     => $data['couponNum'] ?? 0, // 折扣力度/最大抵扣金额
            'couponCode'    => $data['couponCode'] ?? '',
            'pid'           => $data['pid'] ?? '',
            'payStatusType' => $data['payStatusType'],
            'canUseProduct' => (string)($data['canUseProduct'] ?? ''),
            'cappedAmount'  => (int)($data["cappedAmount"] ?? 0), //折扣封顶金额
            'useProducts'   => $data['useProducts'] ?? null,
        ];
    }

    /**
     * [针对 pos]订单券都列为支付方式的数据返回
     *
     * @param $data
     * @return array
     */
    public static function formatOrderPosCoupon($data): array
    {
        $canUseProduct = optional($data->customerCouponRel)->canUseProduct ?? '';
        $useProducts   = null;
        if (!empty($canUseProduct)) {
            $useProducts['list'] = [
                [
                    'canUseProduct' => $canUseProduct,
                    'productLimit'  => 1
                ]
            ];
        }

        $return = [
            'id'            => (string)$data['id'] ?? '',
            'name'          => $data['couponName'] ?? '',
            'status'        => $data['status'] ?? 0,
            'paymentType'   => OrderInfoEnum::POS_ORDER_PAYMENT_COUPON, // 支付类型
            'paymentId'     => $data['couponId'] ?? 0, // 支付 ID
            'payPrice'      => $data['couponDiscountPrice'] ?? 0, // 折扣金额
            'costPrice'     => $data['couponCostPrice'] ?? 0, // 成本金额
            'createdAt'     => $data->createdAt->timestamp ?? 0, // 时间,用于排序
            'couponType'    => $data['couponType'] ?? 0, // 默认为 0 券类型 1代金券 2 商品兑换券 3 折扣券
            'couponNum'     => $data['couponNum'] ?? 0, // 默认为 0 券类型 1代金券 2 商品兑换券 3 折扣券
            'couponCode'    => optional($data->customerCouponRel)->couponCode ?? '',
            'payStatusType' => OrderInfoEnum::POS_ORDER_PAYMENT_PAY_IN,
            'cappedAmount'  => attributeGet($data, "customerCouponRel.cappedAmount", 0),
            'useProducts'   => $useProducts,
        ];

        return self::baseFormatOrderPosData($return);
    }

    /**
     * [针对 pos]订单券都列为支付方式的数据返回
     *
     * @param $data
     * @return array
     */
    public static function formatOrderPosCouponExt($data): array
    {
        $paymentType = CouponExtEnum::switchExtPlatform2OrderPayment($data->extPlatform ?? 0);

        if (!empty($data->couponExtCodeData)) {
            $couponExtCodeData = json_decode($data->couponExtCodeData, true);
        }

        $return = [
            'id'            => (string)$data->id ?? '',
            'name'          => $data->couponExtName ?? '',
            'status'        => $data->couponExtStatus ?? 0,
            'paymentType'   => $paymentType, // 支付类型
            'payPrice'      => $data->couponExtDiscountPrice ?? 0, // 折扣金额
            'costPrice'     => $data->couponExtCostPrice ?? 0, // 成本金额
            'createdAt'     => $data->createdAt->timestamp ?? 0, // 时间,用于排序
            'couponType'    => $data->couponExtType ?? 0, // 默认为 0 券类型 1代金券 2套餐券
            'couponCode'    => $data->couponExtCode,
            'payStatusType' => OrderInfoEnum::POS_ORDER_PAYMENT_PAY_IN,
            'canUseProduct' => (string)($couponExtCodeData['canUseProduct'] ?? ''),
            'useProducts'   => $couponExtCodeData['customData']['useProducts'] ?? null
        ];

        return self::baseFormatOrderPosData($return);
    }

    /**
     * [针对 pos]订单券都列为支付方式的数据返回
     *
     * @param array $data
     * @return array
     */
    public static function formatOrderPosPayStream($data): array
    {

        if ($data['payStatus'] != PayStreamModel::PAY_STATUS_1) {
            return [];
        }

        switch ($data['payChannel']) {
            case PayStreamModel::PAY_CHANNEL_ALI:
            case PayStreamModel::PAY_CHANNEL_WX:
            case PayStreamModel::PAY_CHANNEL_CASH:
                $paymentName = PayStreamModel::PAY_CHANNEL_TEXT[$data['payChannel']] ?? '';
                $paymentType = OrderInfoEnum::POS_ORDER_PAYMENT_COMMON_PAY;
                break;
            case PayStreamModel::PAY_CHANNEL_FY:
                $paymentName = PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$data['payChannelChild']] ?? '';
                $paymentType = OrderInfoEnum::POS_ORDER_PAYMENT_COMMON_PAY;
                break;
            case $data['payChannel'] >= PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT:
                $paymentName = $data['streamCustomPaymentRel']['name'] ?? "不存在的支付方式";
                $paymentType = OrderInfoEnum::POS_ORDER_PAYMENT_CUSTOM_PAY;
                break;
        }

        $return = [
            'id'            => $data['payNo'] ?? '',
            'name'          => $paymentName ?? '',
            'paymentType'   => $paymentType, // 支付类型
            'paymentId'     => $data['payChannel'], // 支付类型
            'payPrice'      => $data['payPrice'] ?? 0, // 折扣金额
            'createdAt'     => $data->createdAt->timestamp ?? 0, // 时间,用于排序
            'payStatusType' => OrderInfoEnum::POS_ORDER_PAYMENT_PAY_IN,
        ];

        return self::baseFormatOrderPosData($return);
    }

    /**
     * [针对 pos]订单券都列为退款支付方式的数据返回
     *
     * @param array $data
     * @return array
     */
    public static function formatOrderPosRefundStream($data): array
    {

        switch ($data['refundChannel']) {
            case PayStreamModel::PAY_CHANNEL_ALI:
            case PayStreamModel::PAY_CHANNEL_WX:
            case PayStreamModel::PAY_CHANNEL_CASH:
                $paymentName = PayStreamModel::PAY_CHANNEL_TEXT[$data['refundChannel']] ?? '';
                $paymentType = OrderInfoEnum::POS_ORDER_PAYMENT_COMMON_PAY;
                break;
            case PayStreamModel::PAY_CHANNEL_FY:
                $paymentName = PayStreamModel::PAY_CHANNEL_CHILD_TEXT[$data['refundChannelChild']] ?? '';
                $paymentType = OrderInfoEnum::POS_ORDER_PAYMENT_COMMON_PAY;
                break;
            case $data['refundChannel'] >= PayStreamModel::PAY_CHANNEL_CUSTOM_PAYMENT:
                $paymentName = $data['streamCustomPaymentRel']['name'] ?? "不存在的支付方式";
                $paymentType = OrderInfoEnum::POS_ORDER_PAYMENT_CUSTOM_PAY;
                break;
        }

        $return = [
            'id'            => $data['refundNo'] ?? '',
            'name'          => $paymentName ?? '',
            'paymentType'   => $paymentType, // 支付类型
            'payPrice'      => $data['refundPrice'] ?? 0, // 折扣金额
            'paymentId'     => $data['refundChannel'], // 支付类型
            'createdAt'     => $data->createdAt->timestamp ?? 0, // 时间,用于排序
            'pid'           => $data['payNo'],
            'payStatusType' => OrderInfoEnum::POS_ORDER_PAYMENT_REFUND,
        ];

        return self::baseFormatOrderPosData($return);
    }

    /**
     * 返回 POS 需要的数据格式
     */
    public function getOrderPosReturn()
    {
        $orderInfo = OrderService::getOrderById($this->shopId, (int)$this->orderId);

        if (empty($orderInfo)) {
            return [];
        }

        $paymentList = [
            'order'       => self::getPosOrder($orderInfo),
            'paymentList' => self::getPosOrderPaymentList($orderInfo),
        ];

        return $paymentList;
    }

    /******* private function *******/

    private function payCustomPayment(array $customPayment)
    {
        // 处理自定义支付的优惠金额
        if (!empty($customPayment)) {
            foreach ($customPayment as $payment) {
                PayService::customPay(
                    $this->shopId,
                    $this->orderId,
                    $payment['payMoney'],
                    $payment['payChannel'],
                    $payment['reckonType']
                );
            }
        }

    }

    private function refundCustomPayment(array $customPayment)
    {
        // 自定义支付退款
        if (!empty($customPayment)) {
            foreach ($customPayment as $payment) {
                PayService::sRefund(
                    $this->shopId,
                    $this->orderId,
                    $payment['payMoney'],
                    '',
                    $payment['id']
                );
            }
        }
    }

    public function refundUserSideOrderPayment($userSidePayment)
    {
        // 支付宝微信退款
        if (!empty($userSidePayment)) {
            foreach ($userSidePayment as $payment) {
                PayService::sRefund(
                    $this->shopId,
                    $this->orderId,
                    $payment['payMoney'],
                    '',
                    $payment['id']
                );
            }
        }
    }

    /**
     * 整理 Order 入库/更新 数据
     * @throws UserException
     */
    private function getInsertOrderData($data, $isUpdate = false): array
    {
        // 获取计算后的价格
        $price = $this->orderCalc->getOrderPriceNow();

        $insertData = [];

        if (!$isUpdate) {
            $insertData = [
                'brandId'        => $this->brandId,
                'shopId'         => $this->shopId,
                'userId'         => $this->userId,
                'sourceType'     => $data['sourceType'],
                'serialNum'      => OrderService::genSerialNum($this->shopId),
                'createdAt'      => time(),
                'isSelfDelivery' => $data['isSelfDelivery'],
                'deliveryType'   => $data['deliveryType'],
                'distributionId' => $data['deliveryAddress']['distributionId'] ?? 0,
                'createdByUid'   => $this->getCurrentUser($data['sourceType'])['id'] ?? 0,
                'createdBy'      => $this->getCurrentUser($data['sourceType'])['username'] ?? '',
                'invoiceStatus'  => $data['isInvoice'] ?
                    CodeEnum::ORDER_INVOICE_STATUS_WAIT : CodeEnum::ORDER_INVOICE_STATUS_DEFAULT
            ];
        } else {
            // 判断是否是从已经完成订单过来的
            $orgOrderInfo = $this->getOrderInfo();

            if (!empty($orgOrderInfo) && $orgOrderInfo->orderStatus == CodeEnum::ORDER_STATUS_FINISHED) {
                // 修改为反结账状态
                $insertData['orderStatus'] = CodeEnum::ORDER_STATUS_REVERSE;
            }

            // 调整支付状态
            $orgOrderInfo = $this->getOrderInfo();
            if (!empty($orgOrderInfo) && $orgOrderInfo->payStatus == CodeEnum::ORDER_PAY_STATUS_PAYED) {
                // 修改为反结账状态
                $insertData['payStatus'] = CodeEnum::ORDER_PAY_STATUS_REVERSE;
            }
        }

        // 容易牵扯到 退款金额,故强制改为 0
        $price['orderShouldPrice']      = OrderCalcService::setPriceNotNegative($price['orderShouldPrice']);
        $price['orderTotalShouldPrice'] = OrderCalcService::setPriceNotNegative($price['orderTotalShouldPrice']);

        // 公共字段
        $insertData['orderId']           = $this->orderId;
        $insertData['originalPrice']     = $price['orderOriginPrice'];
        $insertData['shouldPrice']       = $price['orderShouldPrice'];
        $insertData['orderShouldPrice']  = $price['orderTotalShouldPrice'];
        $insertData['discountPrice']     = $price['orderDiscountPrice'];
        $insertData['couponPrice']       = $price['orderCouponPrice'];
        $insertData['couponCostPrice']   = $price['orderCouponCostPrice'];
        $insertData['realDiscountPrice'] = $price['realDiscountPrice'];
        $insertData['updatedByUid']      = $this->getCurrentUser($data['sourceType'])['id'] ?? 0;
        $insertData['updatedBy']         = $this->getCurrentUser($data['sourceType'])['username'] ?? '';
        $insertData['remark']            = $data['remark'];
        $insertData['updatedAt']         = time();


        return $insertData;
    }

    /**
     * 整理 OrderDetail 入库/更新 数据
     * @throws UserException
     */
    private function getInsertOrderDetailData($data, $isUpdate = false): array
    {
        $insertData = [];

        foreach ($this->orderCalc->getOrderFilterOrderDetail() as $detail) {
            $detail['orderId']      = $this->getOrderId(true);
            $detail['brandId']      = $this->brandId;
            $detail['shopId']       = $this->shopId;
            $detail['createdAt']    = time();
            $detail['updatedAt']    = time();
            $detail['createdByUid'] = $this->getCurrentUser($data['sourceType'])['id'] ?? 0;
            $detail['updatedByUid'] = $this->getCurrentUser($data['sourceType'])['id'] ?? 0;
            $detail['createdBy']    = $this->getCurrentUser($data['sourceType'])['username'] ?? '';
            $detail['updatedBy']    = $this->getCurrentUser($data['sourceType'])['username'] ?? '';
            unset($detail['packageList']);
            $insertData[] = $detail;
        }

        return $insertData;
    }

    /**
     * 整理 OrderExtCouponData 入库/更新 数据
     * @throws UserException
     */
    private function getInsertOrderExtCouponData($data, $isUpdate = false): array
    {
        $insertData = [];
        if ($isUpdate) {
            // 循环做 优惠金额对比
            $orgExtCouponList         = $this->orderCalc->getOrderExtCoupon();
            $orgExtCouponListCodeList = array_column($orgExtCouponList, null, 'couponExtCode');
            // pos 的优惠券信息
            $posExtCouponList = $this->orderCalc->getOrderPosCouponExt();
            foreach ($posExtCouponList as $info) {
                if (empty($orgExtCouponListCodeList[$info['code']])) {
                    continue;
                }
                $orgInfo                    = $orgExtCouponListCodeList[$info['code']];
                $insertDataKey              = $orgInfo['id'];
                $insertData[$insertDataKey] = [];
                // 判断金额是否有调整
                if (bccomp($orgInfo['couponExtDiscountPrice'], $info['couponDiscountPrice']) != 0) {
                    $insertData[$insertDataKey] += [
                        'couponExtDiscountPrice' => $info['couponDiscountPrice']
                    ];
                }

                if (empty($insertData[$insertDataKey])) {
                    unset($insertData[$insertDataKey]);
                } else {
                    $insertData[$insertDataKey] += [
                        'updatedAt'    => time(),
                        'updatedByUid' => $this->getCurrentUser($data['sourceType'])['id'] ?? 0,
                    ];
                }
            }
        }
        return $insertData;
    }

    /**
     * 券包购买入库
     *
     * @param $data
     * @return array
     */
    private function InsertOrderCouponPackage($data): array
    {
        $orderId  = 0;
        $payPrice = 0;

        if (!empty($data['couponPackageId'])) {
            list($orderId, $payPrice) = CouponPackageService::doBuy($data['couponPackageId'], $this->shopId,
                $this->userId);
        }

        return ['orderId' => $orderId, 'payPrice' => $payPrice];
    }

    private function getInsertOrderExternal($data, $extOrder): array
    {
        $insertData = [];
        if (!empty($extOrder) && !empty($extOrder['orderId'])) {
            $insertData[] = [
                'id'           => SnowFlake::nextIdCache(),
                'brandId'      => $this->brandId,
                'shopId'       => $this->shopId,
                'type'         => CodeEnum::ORDER_EXTERNAL_TYPE_COUPON_PACKAGE,
                'orderId'      => $this->orderId,
                'extOrderId'   => $extOrder['orderId'],
                'payPrice'     => $extOrder['payPrice'],
                'createdAt'    => time(),
                'updatedAt'    => time(),
                'createdByUid' => $this->getCurrentUser($data['sourceType'])['id'] ?? 0,
                'updatedByUid' => $this->getCurrentUser($data['sourceType'])['id'] ?? 0
            ];
        }

        return $insertData;
    }

    private function getInsertSelfDelivery($data): array
    {
        $insertData      = [];
        $deliveryAddress = $data['deliveryAddress'];
        if ($data['isSelfDelivery'] == BaseModel::SWITCH_ON || $data['deliveryType'] != 0) {
            $insertData = [
                'id'           => SnowFlake::nextIdCache(),
                'brandId'      => $this->brandId,
                'shopId'       => $this->shopId,
                'orderId'      => $this->orderId,
                'provinceName' => $deliveryAddress['provinceName'] ?? '',
                'cityName'     => $deliveryAddress['cityName'] ?? '',
                'countyName'   => $deliveryAddress['countyName'] ?? '',
                'provinceCode' => $deliveryAddress['provinceCode'] ?? '',
                'cityCode'     => $deliveryAddress['cityCode'] ?? '',
                'countyCode'   => $deliveryAddress['countyCode'] ?? '',
                'detailInfo'   => $deliveryAddress['detailInfo'] ?? '',
                'telNumber'    => $deliveryAddress['telNumber'] ?? '',
                'userName'     => $deliveryAddress['userName'] ?? '',
                'createdAt'    => time(),
                'updatedAt'    => time(),
                'createdByUid' => $this->getCurrentUser($data['sourceType'])['id'] ?? 0,
                'updatedByUid' => $this->getCurrentUser($data['sourceType'])['id'] ?? 0
            ];
        }

        return $insertData;
    }

    private function getInsertCustomPaymentList($data, $isUpdate = false): array
    {
        return $this->orderCalc->getOrderCustomPaymentList();
    }

    private function getInsertRefundCustomPaymentList($data, $isUpdate = false): array
    {
        $data = $this->orderCalc->getOrderRefundCustomPaymentList();

        $noPaid = [];
        foreach ($data as $list) {
            if (!empty($list['id'])) {
                $noPaid[] = $list;
            }
        }
        return $noPaid;
    }

    private function getInsertRefundPosCouponList(): array
    {
        $data = $this->orderCalc->getOrderRefundPosCouponList();

        return $data;
    }

    private function getInsertRefundUserSidePaymentList(): array
    {
        $data = $this->orderCalc->getOrderUserSidePaymentList();

        $noPaid = [];
        foreach ($data as $list) {
            if (!empty($list['id'])) {
                $noPaid[] = $list;
            }
        }
        return $noPaid;
    }

    /**
     * 整理 Order Coupon 入库/更新 数据
     *
     * @param $data
     * @return array
     */
    private function getInsertOrderCouponData($data, $isUpdate = false): array
    {
        $insertData = [];
        // 用户的优惠券
        foreach ($this->orderCalc->getOrderUserCoupon() as $userCouponDetail) {
            $insertData[] = $this->formatInsertOrderCouponData($data, $userCouponDetail);
        }

        // POS 使用的优惠券
        foreach ($this->orderCalc->getOrderPosCoupon() as $posCouponDetail) {
            $insertData[] = $this->formatInsertOrderCouponData($data, $posCouponDetail);
        }

        // 写入退券优惠券
        $orderCouponDataExcludeIds = $this->getInsertRefundPosCouponList();
        foreach ($orderCouponDataExcludeIds as $coupon) {
            $coupon['status']    = OrderCouponSplitModel::STATUS_REVOCATION;
            $coupon['name']      = $coupon['couponName'];
            $coupon['costPrice'] = $coupon['couponCostPrice'];
            $coupon['discount']  = $coupon['couponNum'];
            $insertData[]        = $this->formatInsertOrderCouponData($data, $coupon);
        }
        return $insertData;
    }

    /**
     * 获取小程序入库数据
     *
     * @param array $orderData
     * @param array $orderDetailData
     * @return array
     */
    private function getCustomerOrderData(array $orderData, array $orderDetailData)
    {
        try {
            if (empty($orderDetailData) || empty($orderData) || !in_array($orderData['sourceType'], [
                    CodeEnum::SOURCE_TYPE_MINI,
                    CodeEnum::SOURCE_TYPE_DY_MINI
                ])) {
                return [];
            }

            $insertData['orderId']          = $this->orderId;
            $insertData['brandId']          = $orderData['brandId'];
            $insertData['shopId']           = $orderData['shopId'];
            $insertData['originalPrice']    = $orderData['originalPrice'];
            $insertData['discountPrice']    = $orderData['discountPrice'];
            $insertData['shouldPrice']      = $orderData['shouldPrice'];
            $insertData['orderShouldPrice'] = $orderData['orderShouldPrice'];
            $insertData['count']            = count($orderDetailData);
            $imageList                      = array_column($orderDetailData, 'imageUrl');
            array_splice($imageList, 3);
            $insertData['images']    = implode(',', $imageList);
            $insertData['createdAt'] = time();
            $insertData['updatedAt'] = time();
            return $insertData;
        } catch (\Exception $exception) {
            Log::channel('order')->error('orderHandleService-getCustomerOrderData-error', [
                '$orderData'       => $orderData,
                '$orderDetailData' => $orderDetailData,
                '$exception'       => $exception
            ]);

            return [];
        }
    }

    private function getOrderRefundCouponField($field = 'id'): array
    {
        $data = $this->getInsertRefundPosCouponList();

        if (!empty($data)) {
            return array_column($data, $field);
        }
        return [];
    }

    private function formatInsertOrderCouponData($data, $couponDetail)
    {
        $coupon['id']                  = SnowFlake::nextIdCache();
        $coupon['brandId']             = $this->brandId;
        $coupon['shopId']              = $this->shopId;
        $coupon['orderId']             = $this->getOrderId(true);
        $coupon['customerCouponId']    = $couponDetail['customerCouponId'];
        $coupon['couponId']            = $couponDetail['couponId'];
        $coupon['status']              = $couponDetail['status'] ?? OrderCouponSplitModel::STATUS_WAIT;
        $coupon['couponName']          = $couponDetail['name'];
        $coupon['couponCostPrice']     = $couponDetail['costPrice'];
        $coupon['couponDiscountPrice'] = $couponDetail['couponDiscountPrice'];
        $coupon['couponType']          = $couponDetail['couponType'];
        $coupon['couponNum']           = $couponDetail['discount'];
        $coupon['couponSource']        = $couponDetail['couponSource'];
        $coupon['createdAt']           = time();
        $coupon['updatedAt']           = time();
        $coupon['createdByUid']        = $this->getCurrentUser($data['sourceType'])['id'] ?? 0;
        $coupon['updatedByUid']        = $this->getCurrentUser($data['sourceType'])['id'] ?? 0;

        return $coupon;
    }

    /**
     * 整理 Order Discount 入库/更新 数据
     *
     * @param $data
     * @return array
     * @throws UserException
     */
    private function getInsertOrderDiscount($data, $isUpdate = false): array
    {
        $insertData = [];

        $detail = $this->orderCalc->getOrderPosDiscount();
        // 处理自定义支付的优惠金额
        if (!empty($detail) && $detail['discountType'] != 0) {
            $insertData[] = [
                'id'              => SnowFlake::nextIdCache(),
                'orderId'         => $this->getOrderId(true),
                'brandId'         => $this->brandId,
                'shopId'          => $this->shopId,
                'discountType'    => $detail['discountType'],
                'discountPrice'   => $detail['discountPrice'],
                'discountNum'     => $detail['discountNum'],
                'customPaymentId' => 0,
                'createdAt'       => time(),
                'updatedAt'       => time(),
                'createdByUid'    => $this->getCurrentUser($data['sourceType'])['id'] ?? 0,
                'updatedByUid'    => $this->getCurrentUser($data['sourceType'])['id'] ?? 0
            ];
        }

        // 处理自定义支付的优惠金额
        $customPayment = $this->orderCalc->getOrderCustomPaymentList();
        if (!empty($customPayment)) {
            foreach ($customPayment as $payment) {
                if ($payment['reckonType'] == CustomPaymentEnum::RECKON_TYPE_DISCOUNT) {
                    $insertData[] = [
                        'id'              => SnowFlake::nextIdCache(),
                        'orderId'         => $this->orderId,
                        'brandId'         => $this->brandId,
                        'shopId'          => $this->shopId,
                        'discountType'    => CodeEnum::ORDER_DISCOUNT_TYPE_CUSTOM_PAY,
                        'discountPrice'   => $payment['payMoney'],
                        'discountNum'     => 0,
                        'customPaymentId' => $payment['payChannel'],
                        'createdAt'       => time(),
                        'updatedAt'       => time(),
                        'createdByUid'    => $this->getCurrentUser($data['sourceType'])['id'] ?? 0,
                        'updatedByUid'    => $this->getCurrentUser($data['sourceType'])['id'] ?? 0
                    ];
                }
            }
        }


        return $insertData;
    }

    /**
     * 格式化 不(可) 用 优惠券
     *
     * @param $couponList
     * @return array[]
     */
    private function formatOutCouponList($couponList): array
    {
        $return = [
            'disable' => [],
            'enable'  => []
        ];

        foreach ($couponList['disableCouponList'] as $coupon) {
            unset(
                $coupon['userId'],
                $coupon['coupon_shop_rel'],
                $coupon['isWechatNotice'],
                $coupon['isSmsNotice']
            );

            if (!isset($coupon['couponType'])) {
                $coupon['couponType'] = $coupon['type'];
            }
            $return['disable'][] = $coupon;
        }

        foreach ($couponList['enableCouponList'] as $coupon) {
            unset(
                $coupon['userId'],
                $coupon['coupon_shop_rel'],
                $coupon['isWechatNotice'],
                $coupon['isSmsNotice']
            );
            if (!isset($coupon['couponType'])) {
                $coupon['couponType'] = $coupon['type'];
            }
            $return['enable'][] = $coupon;
        }

        return $return;
    }

    /**
     * 获取用户修改人
     *
     * @param $sourceType
     * @return array|Authenticatable
     * @throws UserException
     */
    private function getCurrentUser($sourceType)
    {
        switch ($sourceType) {
            case CodeEnum::SOURCE_TYPE_MINI:
            case CodeEnum::SOURCE_TYPE_DY_MINI:
            case CodeEnum::SOURCE_TYPE_MERCHANT_CHECK_COUPON:
                return [];
            default:
                return AuthService::getAuthUser();

        }
    }

    public function switchDyOrderId(string $dyOrderId)
    {
        $orderInfo       = self::getOrderInfoByThirdOrderId($dyOrderId);
        $this->orderInfo = $orderInfo;
        $this->orderId   = $orderInfo->orderId;
    }

    /**
     * @return int
     */
    public function getUserId(): int
    {
        return $this->userId;
    }

    /**
     * 设置用户 ID
     *
     * @param $request
     */
    public function setUserId($request): void
    {
        $this->userId = CustomerPlatformService::getUserId($request);
    }

    public function setDyUserId(string $unionId): void
    {
        $this->userId = CustomerPlatformService::getUserIdByUnionId($unionId, PlatformCodeEnum::PLATFORM_APPLET_DOUYIN);
    }
}
